package com.kyub.spring.gears.introspect;

import com.kyub.spring.gears.model.*;
import com.kyub.spring.gears.services.DaoService;
import com.kyub.spring.gears.PrjLogger;
import org.springframework.util.StringUtils;

import javax.naming.ConfigurationException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;


/**
 * Factory fro pojo descriptors
 */
public class PojoDescriptorFactory extends MetadataClassFactory {


    private PropertyDescriptorFactory propertyDescriptorFactory;


    public PojoDescriptorFactory(PojoRegistry registry) {
        super(registry);
        propertyDescriptorFactory = new PropertyDescriptorFactory(registry);
    }


    public PojoDescriptor buildSimpleDescriptorByClass(Class pojoClass)
            throws ConfigurationException {

        PojoDescriptor pojoDescriptor = new PojoDescriptor();
        pojoDescriptor.setPojoClass(pojoClass);
        final String basePojoName = StringUtils.uncapitalize(pojoClass.getSimpleName());
        pojoDescriptor.setName(basePojoName);
        final Method[] methods = pojoClass.getMethods();
        pojoDescriptor.setIdProperty(checkIdProperty(basePojoName, methods));

        final PojoRegistryEntry pojoRegistryEntry = registry.getPojoConf(basePojoName);
        pojoDescriptor.setEditable(pojoRegistryEntry.getEditable());
        pojoDescriptor.setDeletable(pojoRegistryEntry.getDeletable());
        pojoDescriptor.setInsertable(pojoRegistryEntry.getInsertable());
        pojoDescriptor.setAllowedRoles(pojoRegistryEntry.getAllowedRoles());
        pojoDescriptor.setDeletableRoles(pojoRegistryEntry.getDeletableRoles());
        pojoDescriptor.setInsertableRoles(pojoRegistryEntry.getInsertableRoles());
        pojoDescriptor.setEditableRoles(pojoRegistryEntry.getEditableRoles());


        return pojoDescriptor;
    }

    public PojoDescriptor buildNormalizedDescriptorByClass(Class pojoClass)
            throws ConfigurationException {

        PojoDescriptor pojoDescriptor = buildSimpleDescriptorByClass(pojoClass);


        final Method[] methods = pojoClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method methodProp = methods[i];
            if (!collectionTypes.contains(methodProp.getReturnType()))
                checkMethod(pojoDescriptor, methodProp);
        }
        propertyDescriptorFactory.buildFieldsList(pojoDescriptor);
        return pojoDescriptor;
    }

    public PojoDescriptor buildDescriptorByClass(Class pojoClass)
            throws ConfigurationException {

        PojoDescriptor pojoDescriptor = buildSimpleDescriptorByClass(pojoClass);


        final Method[] methods = pojoClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method methodProp = methods[i];
            checkMethod(pojoDescriptor, methodProp);
        }
        propertyDescriptorFactory.buildFieldsList(pojoDescriptor);
        propertyDescriptorFactory.buildFieldForm(pojoDescriptor);
        return pojoDescriptor;
    }

    public Map loadRealtedValues(PojoDescriptor descriptor, PojoRegistry pojoRegistry) {

        final Map related = new HashMap();

        Iterator<PropertyDescriptor> i = descriptor.getProperties().iterator();
        while (i.hasNext()) {
            PropertyDescriptor propertyDescriptor = i.next();
            if (propertyDescriptor instanceof RelationPropertyDescriptor) {
                final RelationPropertyDescriptor p2 = (RelationPropertyDescriptor) propertyDescriptor;
                final DaoService service = pojoRegistry.getPojoConf(p2.getPojoDescr().getName()).getDao();
                related.put(p2.getName(), service.list());
            }
            if (propertyDescriptor instanceof CollectionPropertyDescriptor) {
                final CollectionPropertyDescriptor p2 = (CollectionPropertyDescriptor) propertyDescriptor;
                related.putAll(loadRealtedValues(p2.getPojoDescr(), pojoRegistry));
            }
        }


        return related;
    }

    private void checkMethod(PojoDescriptor pojoDescriptor, Method methodProp)
            throws ConfigurationException {
        PrjLogger.debug(this, "Esamino " + methodProp.getName());
        if (methodProp.getName().startsWith("get")) {
            PrjLogger.debug(this, methodProp.getName() + " e' un getter");

            propertyDescriptorFactory.addDescriptorByMethod(methodProp, pojoDescriptor);


        }
    }


}
